# !/usr/bin/env python3
# -*- coding: utf-8 -*-


import os
import xml.etree.ElementTree as EleTree
from util.lib import pretty_xml, transfor_data_set_to_node_set
from util.topo_adapter import get_topo_set
from util.flow_adapter import get_route_path


def _get_flow_set(flow_xml):
    # 首先从flow_xml中提取出所有需要FL api进行映射的流量
    tree = EleTree.parse(flow_xml)
    flow_ele_set = tree.findall('flow')

    flow_set = []

    for flow_ele in flow_ele_set:
        # 首先判断该流量是否需要FL api进行映射
        fl_api_flag = flow_ele.findtext('fl_api_flag')
        # 如果该流量不需要FL api进行映射
        if fl_api_flag == '0':
            continue

        # 流id
        flow_id = flow_ele.findtext('stream_id')
        # redundant_flag
        redundant_flag = flow_ele.findtext('redundant')
        # 五元组信息
        src_ip = flow_ele.findtext('src_ip')
        dst_ip = flow_ele.findtext('dst_ip')
        src_port = flow_ele.findtext('src_port')
        dst_port = flow_ele.findtext('dst_port')
        ip_protocol = flow_ele.findtext('ip_protocol')
        fivetuple_mask = flow_ele.findtext('fivetuple_mask')
        dst_mac = flow_ele.findtext('dst_mac')
        # 流类型
        flow_type = flow_ele.findtext('flow_type')
        if flow_type == 'ST':
            flow_type = 'TT'
        elif flow_type == 'AVB':
            flow_type = 'AVB'
        else:
            print('ERROR - flow_xml文件配置错误：目前不支持BE流。')
            exit(0)

        flow_set.append({
            'flow_id': flow_id,
            'redundant_flag': redundant_flag,
            'ip_protocol': ip_protocol,
            'dst_port': dst_port,
            'src_port': src_port,
            'dst_ip': dst_ip,
            'src_ip': src_ip,
            'five_tuple_mask': fivetuple_mask,
            'flow_type': flow_type,
            'cookies': '10',
            'dst_mac': dst_mac
        })

    return flow_set


def add_src_node_to_flow_set(flow_set, route_set):
    for flow_ele in flow_set:
        for route_ele in route_set:
            if int(flow_ele['flow_id']) == route_ele['flow_id']:
                src_node_id = route_ele['src_node_id']
                first4 = hex(int(src_node_id) >> 8 & 0xf)[2:]
                mid4 = hex(int(src_node_id) >> 4 & 0xf)[2:]
                last4 = hex(int(src_node_id) & 0xf)[2:]
                src_mac = '66:26:62:' + first4 + mid4 + ':' + last4 + '8:00'
                flow_ele.update({'node_id': str(src_node_id),
                                 'src_mac': src_mac})
                break
    return


def generate_fl_api_xml(node_set, fl_api_xml_folder):
    # 将各个节点的流量信息分别写入不同的xml文件
    # 首先需要将文件夹下的文件清空
    filelist = os.listdir(fl_api_xml_folder)
    for f in filelist:
        os.remove(fl_api_xml_folder + f)
    for each_node in node_set:
        # 根据node_id生成xml文件的名称
        xml = fl_api_xml_folder + \
              'fl_api_cfg_node_' + each_node['node_id'] + '.xml'
        # print(xml)
        root_ele = EleTree.Element('fl_api_cfg')
        node_ele = EleTree.SubElement(root_ele, "node")
        node_id = EleTree.SubElement(node_ele, "node_id")
        node_id.text = each_node['node_id']

        flow_set = each_node['data_set']
        for flow in flow_set:
            entry = EleTree.SubElement(node_ele, "entry")
            for key in flow:
                ele = EleTree.SubElement(entry, key)
                ele.text = flow[key]

        tree = EleTree.ElementTree(root_ele)
        pretty_xml(root_ele, '\t', '\n')
        tree.write(xml,
                   encoding='utf-8',
                   xml_declaration=True)
    return


def assemble_fl_api_xml(flow_xml,
                        topo_xml,
                        fl_api_xml_folder):
    # 1.根据topo_xml，获取topo_set
    topo_set = get_topo_set(topo_xml)
    print("1. topo_set: ")
    [print(entry) for entry in topo_set]
    # 2.获取流的路由路径
    route_set = get_route_path(flow_xml, topo_set)
    print("2. route_set: ")
    [print(entry) for entry in route_set]

    # 3.获取flow_set
    flow_set = _get_flow_set(flow_xml)
    print("3. flow_set: ")
    [print(entry) for entry in flow_set]

    # 4.更新flow_set，链路源节点和源mac
    add_src_node_to_flow_set(flow_set, route_set)

    # 5.flow_set转化为node_set
    node_set = transfor_data_set_to_node_set(flow_set)

    # 生成xml
    generate_fl_api_xml(node_set, fl_api_xml_folder)

    return


def main():
    flow_xml = '../input/flow_feature.xml'
    topo_xml = '../input/topo_feature.xml'
    fl_api_xml_folder = '../output/fl_api/'
    assemble_fl_api_xml(flow_xml,
                        topo_xml,
                        fl_api_xml_folder)
    return


if __name__ == "__main__":
    main()
